home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Pascal Super Library
/
Pascal Super Library (CW International)(1997).bin
/
TSR
/
STAY50
/
FLISTU.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1988-11-28
|
17KB
|
341 lines
{$I direct.inc}
{───────────────────────────────────────────────────────────────────────────}
{ FLISTU.PAS File list unit }
{ }
{ Copyright (C) 1988 Lane H.Ferris All Rights Reserved }
{───────────────────────────────────────────────────────────────────────────}
{ Dinsaurs live }
{───────────────────────────────────────────────────────────────────────────}
unit FLISTU ;
{────────────────────────────────────────────────────────────────────────}
interface
{────────────────────────────────────────────────────────────────────────}
type
filenamestr = string[64] ;
Function FLopen (pFilename : filenamestr ) : integer ;
Procedure FLclose (pFilename : filenamestr ) ;
Procedure FLgetNr (pLineNr :word; var Strptr:string ) ;
{────────────────────────────────────────────────────────────────────────}
implementation
{────────────────────────────────────────────────────────────────────────}
uses macros ,
SR50subs ,
sr50 {debugging only} ;
type
SeekLstptr = ^SeekLstType ;
SeekLstType = record { Seek Chain Entry }
SeekLink : SeekLstptr ; { addr of next entry or nil }
SeekLineNr : word ; { Line Nr at this location }
SeekLastNr : word ; { Last Line number in buf }
SeekFileLoc : longint ; { Byte location within file }
Seektextlth : word ; { actual text bytes in buf }
{SeekLstType} end ;
FLbitmap = array[0..511] of byte ;
const
FLhasopenfile : boolean = false ;
_4K = 4*1024 ; { Blk file buffer size }
crlf : word = $0A0D ; { word of cr lf }
var
FLfilename : filenamestr ; { last opened file }
FLinfile : file ; { File of byte }
FLfilesize : longint ; { Nr bytes in file }
FlBufptr : pointer ; { ptr to file buffer }
FLmapptr : ^FLbitmap ; { 1 bit for each txtrec }
FLbytesinbuf : word ; { bytes in blk buffer }
SeekLstAnchor : SeekLstPtr ; { Anchor for Seek list }
BufSeekLst : SeekLstptr ; { List represented in buf}
{────────────────────────────────────────────────────────────────────────}
{ SetLastLineNr }
{────────────────────────────────────────────────────────────────────────}
{ count down the buffer for crlf and return last line number found }
{ set a bit in a large bitstring to indicate where a line exists }
{────────────────────────────────────────────────────────────────────────}
Procedure SetLastLineNr (pLstptr : SeekLstptr ) ;
var
locptr :SeekLstptr ;
txtlines :word ;
txtptr :pointer ;
Mapbyteptr :^byte ;
i,j :word ;
begin
locptr := pLstptr ;
txtptr := FLbufptr ;
txtlines := 0 ;
pLstptr^.SeekTextlth := 0 ;
fillchar(FLmapptr^, { say no text with crlf }
sizeof(FLmapptr^),0) ;
FLmapptr^[0] := $80 ; { set bit for first record }
for i := 0 to FLbytesinbuf do begin { scan for more records }
if word(txtptr^) = crlf then begin
inc(txtlines) ;
pLstptr^.Seektextlth := i+2 ;
j := i+2 ; { beginning of next txt rec }
Mapbyteptr := ptr(vec(FLmapptr).seg,vec(FLmapptr).ofs+(j DIV 8)) ;
Mapbyteptr^ := Mapbyteptr^ or ($80 shr (j MOD 8)) ; { set bit }
end {if word..} ;
incptr(txtptr,1) ;
end ;
pLstptr^.SeeklastNr := pLstptr^.SeekLineNr+txtlines-1 ;
end { Procedure SetLastLineNr } ;
{────────────────────────────────────────────────────────────────────────}
{ FLclose }
{────────────────────────────────────────────────────────────────────────}
Procedure FLclose(pFilename : filenamestr ) ;
var
seekptr : Seeklstptr ;
begin
close(FLinfile) ;
if IOresult <> 0 then
Errormsg(warnlevel, 'FLopen cannot close '+ pfilename ) ;
while SeekLstAnchor <> nil do { free all seeklist entries }
begin
seekptr := SeekLstAnchor^.seeklink ;
dispose(SeekLstAnchor) ;
SeekLstAnchor := seekptr ;
end {while..};
freemem(FLbufptr,_4K) ; { memory for Block file buf }
freemem(FLmapptr,sizeof(Flmapptr^)) ; { memory for txtrec bitmap }
FLhasopenfile := false ;
end {FLclose} ;
{────────────────────────────────────────────────────────────────────────}
{ FLopen }
{────────────────────────────────────────────────────────────────────────}
Function FLopen (pFilename : filenamestr ) : integer ;
var
Openresult : integer ;
begin
{$I-}
if FLhasopenfile then
FLclose(FLFilename) ; { close previous file }
FLfilename := pFilename ;
assign( FLinfile, pFilename ) ; { open new file }
reset ( FLinfile,1 ) ;
{$I+}
Openresult := IOresult ;
FLopen := Openresult ;
if Openresult <> 0 then begin
Errormsg(warnlevel, 'FLopen: cannot open '+pFilename ) ;
exit ;
end {if ioresult} ;
FLhasopenfile := true ;
FLfilesize := filesize(FLinfile) ;
If Maxavail < _4K+512 then begin
errormsg(warnlevel,'FLopen: Heap overflow') ;
FlOpen := 203 ; exit ;
end ;
getmem(FLbufptr,_4K) ; { memory for Block file buf }
getmem(FLmapptr, { memory for txtrec bitmap }
sizeof(FLmapptr^)) ;
fillchar(FLmapptr^,
sizeof(FLmapptr^),0) ; { say no text with crlf }
if FLbufptr = nil then begin
Errormsg(warnlevel, 'FLopen: no memory for File buffer') ;
FLclose(Flfilename) ;
FLhasopenfile := false ;
exit ;
end {if nil..} ;
{ prime the input buffer }
Blockread(FLinfile,FLbufptr^,_4k,Flbytesinbuf) ;
new(SeekLstAnchor) ; { anchor list of seek locs }
with SeekLstAnchor^ do begin
SeekLink := nil ;
SeekLineNr := 1 ;
SeekFileloc := 0 ;
SetLastLineNr(SeekLstAnchor); { scan and set last line Nr }
end {with SeekLstAnchr} ;
BufSeekLst := SeekLstAnchor ; { Current List in buffer }
end {Procedure FLopen} ;
{────────────────────────────────────────────────────────────────────────}
{ FLbufread }
{────────────────────────────────────────────────────────────────────────}
{ Reads another buffer of text from the physical file }
{────────────────────────────────────────────────────────────────────────}
Procedure FLbufread (pLineNr : word ) ;
var
locptr : SeekLstptr ;
done : boolean ;
begin
locptr := SeekLstAnchor ;
done := false ;
while
(locptr^.SeekLink <> nil) and
(NOT done) do { search SeekLine list to find }
with locptr^ do { lower linenumber than requested }
if SeekLink^.SeekLineNr { parameter line number }
> pLineNr then done := true
else locptr := SeekLink ;
{ locptr now has low linenumber }
if locptr^.Seektextlth = 0 then { Check for End of file }
begin
BufSeekLst := locptr ;
exit ; end ;
if locptr^.SeekLastNr >= pLineNr
then {ok} { pLineNr is within this buffer }
else begin { else have to read forward }
new(locptr^.SeekLink) ; { allocate another list entry }
locptr^.seeklink^ := Locptr^ ; { fill in the Seeklist entry }
locptr := locptr^.seeklink ; { point to new seeklist entry }
locptr^.seeklink := nil ;
locptr^.SeekLineNr := locptr^.SeekLastNr+1 ; { next file line Nr }
locptr^.SeekFileLoc := Locptr^.SeekFileloc { Seek file byte from.. }
+ Locptr^.SeekTextlth ; { last seek + full lines}
end {else begin} ;
{ VM386 bug: 06 error if directory is changed }
Seek(FLinfile,locptr^.SeekFileLoc) ;
unfreeze;
if IOresult <> 0 then
Errormsg(warnlevel, 'FLread: seek error in '+FLFilename ) ;
Blockread(FLinfile,FLbufptr^,_4k,FLbytesinbuf) ;
SetLastLineNr(locptr) ; { scan and set last line Nr }
BufSeekLst := locptr ; { current SeekLst in buffer }
end { Procedure FLbufread } ;
{────────────────────────────────────────────────────────────────────────}
{ BitScanOfs }
{────────────────────────────────────────────────────────────────────────}
{ bitcount := BitScanofs(FLmapptr^,size(FLmapptr^),bitcount) ; }
{ scans a large bit string and returns position of next bit }
{────────────────────────────────────────────────────────────────────────}
Function BitScanOfs(BitMapPtr : pointer;
BitMapsize,bitcount :word) :word ;
Begin
Inline(
$29/$D2 { sub dx,dx ;}
/$8B/$86/>BITCOUNT { mov ax,[bp+>bitcount] ; position of last bit returned}
/$B9/$08/$00 { mov cx,8 ;}
/$F7/$F1 { div cx ; position of byte last returned}
/$89/$D1 { mov cx,dx ; save bitpos MOD 8}
/$89/$C3 { mov bx,ax ; save offset to byte}
/$C4/$BE/>BITMAPPTR { les di,[bp+>BitMapPtr] ; pointer to full bitstring}
/$01/$DF { add di,bx ; point to byte}
/$26 { es: ;}
/$FF/$35 { push [di] ; save the current byte}
/$57 { push di ; save the ofs to it}
/$B0/$FF { mov al,$FF ;}
/$D2/$E8 { shr al,cl ; 0 bits ahead/1 bits behind old bit}
/$26 { es: ;}
/$20/$05 { and 0[di],al ; kill the bit last returned}
/$29/$C0 { sub ax,ax ; scan for a byte containing a bit}
/$8B/$8E/>BITMAPSIZE { mov cx,[bp+>BitMapsize];}
/$F3/$AE { repe scasb ; repeat while equal to zero}
/$4F { dec di ; set pointer to last byte}
/$26 { es: ;}
/$8A/$1D { mov bl,0[di] ; fetch byte}
/$2B/$BE/>BITMAPPTR { sub di,[bp+>BitMapPtr] ; fetch byte count scanned}
/$29/$D2 { sub dx,dx ;}
/$89/$F8 { mov ax,di ;}
/$B9/$08/$00 { mov cx,8 ;}
/$F7/$E1 { mul cx ; now have bit count}
{ ; now add bits in the stop byte}
/$D0/$E3 {L1: sal bl,1 ; shift out any bit that may be there}
/$72/$03 { jc L2 ; carry if bit is shifted out}
/$40 { inc ax ; count the non-bit}
/$E2/$F9 { loop L1 ; shift until we find the bit}
/$5F {L2: pop di ; replace the modified bit pattern}
/$26 { es: ;}
/$8F/$05 { pop [di] ;}
/$89/$46/$FE { mov [bp-2],ax ; stow the function return value}
) ;
End {BitScanOfs} ;
{────────────────────────────────────────────────────────────────────────}
{ MaptoBufofs }
{────────────────────────────────────────────────────────────────────────}
{ Search for a bit in the buffer bit map which }
{ represents this line number. Return its offset in buffer }
{────────────────────────────────────────────────────────────────────────}
Function MaptoBufofs (pLineNr :word) :word ;
var
i :word ;
bitcount :word ;
maxbits :word ;
Begin
{ scan the bit map until we find pLineNr bit }
{ there is always at least one bit, viz, the first line in buffer bit }
i := BufSeekLst^.SeekLineNr-1 ; { first lineNr in this buffer }
bitcount := 0 ;
maxbits := sizeof(FLmapptr^)*8 ; { number of slots in bitmap }
MaptoBufofs := 0 ;
REPEAT
bitcount := BitScanofs(FLmapptr,sizeof(FLmapptr^),bitcount) ;
if bitcount <= maxbits then inc(i) ;
if i >= pLineNr then begin
MaptoBufofs := bitcount ; { a bit displacement and a byte }
exit ; { displacement are equivalent }
end ;
inc(bitcount) ; { dont read old bit again }
UNTIL (bitcount >= maxbits) ;
End { MaptoBufofs } ;
{────────────────────────────────────────────────────────────────────────}
{ FLgetNr }
{────────────────────────────────────────────────────────────────────────}
{ Search for Line Nr in current buffer }
{ Search for Line number , return actual line nr found }
{────────────────────────────────────────────────────────────────────────}
Procedure FLgetNr (pLineNr :word; var Strptr:string ) ;
var
Seekptr : SeekLstptr ;
Hdptr : pointer ;
Edptr : pointer ;
found : boolean ;
Outstr : string absolute Strptr ;
thisnr : word ;
txtlth : word ;
begin
Seekptr := BufSeekLst ;
found := false ;
while NOT found do begin
if ((pLineNr >= seekptr^.SeekLineNr) { read another buffer when }
and { line nr not in current buf }
(pLineNr <= seekptr^.SeekLastNr))
then found := true ;
if NOT found then begin
FLbufread(pLineNr) ;
seekptr := BufSeekLst ;
end {if..} ;
if seekptr^.seektextlth = 0 { check for end of file }
then found := true ;
end {while} ;
Hdptr := FlBufptr ; { search for desired line Nr }
Edptr := Hdptr ; { search for a its bit in map }
thisnr := seekptr^.SeekLineNr ;
incptr(Hdptr, MaptoBufofs(pLineNr )) ;
incptr(Edptr, MaptoBufofs(pLineNr+1 )) ;
txtlth := ptrdiff(Edptr,Hdptr) ;
if txtlth > 255 then txtlth := 255 ;
Outstr[0] := char(txtlth) ;
move(Hdptr^,Outstr[1],txtlth) ;
if txtlth > 0 then {found ok} { return ptr if LineNr found }
else begin { else return EOF indication }
str(seekptr^.SeekLastNr,OutStr) ;
Outstr := #26+Outstr ;
end ;
end { Procedure FLgetNr } ;
{────────────────────────────────────────────────────────────────────────}
{ initialization }
{────────────────────────────────────────────────────────────────────────}
begin { FLST initialization }
SeekLstAnchor := nil ;
end { FLST initialization } .